<!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>JS 数据类型相关的 15 道面试题：</title>
        
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/Microsoft/vscode/extensions/markdown-language-features/media/markdown.css">
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/Microsoft/vscode/extensions/markdown-language-features/media/highlight.css">
        
        <style>
.task-list-item { list-style-type: none; } .task-list-item-checkbox { margin-left: -20px; vertical-align: middle; }
</style>
        <style>
            body {
                font-family: -apple-system, BlinkMacSystemFont, 'Segoe WPC', 'Segoe UI', 'Ubuntu', 'Droid Sans', sans-serif;
                font-size: 14px;
                line-height: 1.3;
            }
        </style>
        
        
    </head>
    <body class="vscode-light">
        <h4 id="js-%e6%95%b0%e6%8d%ae%e7%b1%bb%e5%9e%8b%e7%9b%b8%e5%85%b3%e7%9a%84-15-%e9%81%93%e9%9d%a2%e8%af%95%e9%a2%98">JS 数据类型相关的 15 道面试题：</h4>
<ul>
<li>JS 有哪些原始数据类型？</li>
<li>除了上述数据类型还有哪些？</li>
<li>值类型与引用类型有什么区别？</li>
<li>如何判断上述数据类型？</li>
<li>Undefined 与 Null 有什么区别？</li>
<li>如何判断空对象？</li>
<li>如何判断对象是否有某个属性？</li>
<li>数组都有哪些常用的方法？</li>
<li>map()与 forEach()有什么相同处，什么不同处？</li>
<li>slice()与 splice()有什么区别？</li>
<li>简述 reduce()的使用</li>
<li>普通函数与构造函数有什么区别？</li>
<li>Set、Map 是什么？</li>
<li>Set、Map 与 WeakSet、WeakMap 有什么不同？</li>
<li>类型的隐式转换有哪些？</li>
</ul>
<hr>
<h4 id="%e9%97%aejs-%e6%9c%89%e5%93%aa%e4%ba%9b%e5%8e%9f%e5%a7%8b%e6%95%b0%e6%8d%ae%e7%b1%bb%e5%9e%8b"><strong>问：JS 有哪些原始数据类型？</strong></h4>
<p><strong>答：</strong></p>
<p>7 种原始数据类型：String、Number、Boolean、Undefined、Null、Object、Symbol；</p>
<p>其中 String、Number、Boolean、Undefined、Null 属于值类型，Object 属于引用类型，Symbol 是 ES6 中新增的数据类型代表独一无二。</p>
<hr>
<h4 id="%e9%97%ae%e9%99%a4%e4%ba%86%e4%b8%8a%e8%bf%b0%e6%95%b0%e6%8d%ae%e7%b1%bb%e5%9e%8b%e8%bf%98%e6%9c%89%e5%93%aa%e4%ba%9b"><strong>问：除了上述数据类型还有哪些？</strong></h4>
<p><strong>答：</strong></p>
<p>因为 JS 所有事物都是对象，所以除了上述 7 种原始数据类型，还有 Array、Function、Date、正则、Set、Map 等。</p>
<hr>
<h4 id="%e9%97%ae%e5%80%bc%e7%b1%bb%e5%9e%8b%e4%b8%8e%e5%bc%95%e7%94%a8%e7%b1%bb%e5%9e%8b%e6%9c%89%e4%bb%80%e4%b9%88%e5%8c%ba%e5%88%ab"><strong>问：值类型与引用类型有什么区别？</strong></h4>
<p><strong>答：</strong></p>
<p>JS 数据以栈内存，堆内存存储在内存中，值类型的数据按值存储在栈内存中，引用类型的数据存储的是一个指针，按指针指向堆内存中对应的值。在赋值操作时，值类型按值传递，引用型按引用关系传递。</p>
<hr>
<h4 id="%e9%97%ae%e5%a6%82%e4%bd%95%e5%88%a4%e6%96%ad%e4%b8%8a%e8%bf%b0%e7%b1%bb%e5%9e%8b"><strong>问：如何判断上述类型？</strong></h4>
<p><strong>答：</strong></p>
<p>值类型的一般使用 typeof,返回其类型值的小写字符串；</p>
<pre><code class="language-javascript"><div><span class="hljs-comment">// 一般值类型的判断（String、Number、Boolean）</span>
<span class="hljs-keyword">var</span> a = <span class="hljs-number">1</span>,
  b = <span class="hljs-string">'hello'</span>,
  c = <span class="hljs-literal">true</span>;
<span class="hljs-built_in">console</span>.log(<span class="hljs-keyword">typeof</span> a === <span class="hljs-string">'number'</span>); <span class="hljs-comment">// true</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-keyword">typeof</span> b === <span class="hljs-string">'string'</span>); <span class="hljs-comment">// true</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-keyword">typeof</span> c === <span class="hljs-string">'boolean'</span>); <span class="hljs-comment">// true</span>
</div></code></pre>
<p>Undefined 比较特殊，也可以使用 typeof，返回‘undefined’，结合取非来判断：</p>
<pre><code class="language-javascript"><div><span class="hljs-comment">// 是否是Undefined类型</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isUndefined</span>(<span class="hljs-params">value</span>)</span>{
  <span class="hljs-keyword">if</span>(!value &amp;&amp; <span class="hljs-keyword">typeof</span> ===<span class="hljs-string">'undefined'</span>)<span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
  <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
}

<span class="hljs-comment">// 衍生：变量是否已经定义，并且是Undefined类型</span>
<span class="hljs-keyword">var</span> isDefined=<span class="hljs-literal">false</span>,isUndefined=<span class="hljs-literal">false</span>;
<span class="hljs-keyword">try</span>{
  isDefined=<span class="hljs-literal">true</span>;
  <span class="hljs-keyword">if</span>(!a &amp;&amp; <span class="hljs-keyword">typeof</span> a===<span class="hljs-string">'undefined'</span>)isUndefined=<span class="hljs-literal">true</span>;

}<span class="hljs-keyword">catch</span>(err){
  isDefined=<span class="hljs-literal">false</span>;
}

<span class="hljs-built_in">console</span>.log(isDefined);
<span class="hljs-built_in">console</span>.log(isUndefined);
</div></code></pre>
<p>Null 比较特殊，typeof 返回'object',结合取非来判断：</p>
<pre><code class="language-javascript"><div><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isNull</span>(<span class="hljs-params">value</span>) </span>{
  <span class="hljs-keyword">if</span> (!value &amp;&amp; <span class="hljs-keyword">typeof</span> value === <span class="hljs-string">'object'</span>) <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
  <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
}
</div></code></pre>
<p>对于引用型的 Object、Array、function 的判断:</p>
<p>数组使用 Array.isArray()；</p>
<p>对象使用 toString()判断原始值是否为[object Object]；</p>
<p>函数直接使用 typeof，是否为‘function’。</p>
<pre><code class="language-javascript"><div><span class="hljs-comment">// 数组的判断</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isArray</span>(<span class="hljs-params">value</span>) </span>{
  <span class="hljs-keyword">if</span> (<span class="hljs-built_in">Array</span>.isArray(value)) <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
  <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
}

<span class="hljs-comment">// 对象的判断</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isObj</span>(<span class="hljs-params">value</span>) </span>{
  <span class="hljs-keyword">if</span> (value.toString() === <span class="hljs-string">'[object Object]'</span>) <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
  <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
}

<span class="hljs-comment">// 函数的判断</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isFunction</span>(<span class="hljs-params">value</span>) </span>{
  <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> value === <span class="hljs-string">'function'</span>) <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
  <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
}
</div></code></pre>
<hr>
<h4 id="%e9%97%aeundefined-%e4%b8%8e-null-%e6%9c%89%e4%bb%80%e4%b9%88%e5%8c%ba%e5%88%ab"><strong>问：Undefined 与 Null 有什么区别？</strong></h4>
<p><strong>答：</strong></p>
<p>Undefined 表示已经定义但未赋值，Null 代表一个空指针在栈内存中找不到其值地址指向。</p>
<hr>
<h4 id="%e9%97%ae%e5%a6%82%e4%bd%95%e5%88%a4%e6%96%ad%e7%a9%ba%e5%af%b9%e8%b1%a1"><strong>问：如何判断空对象？</strong></h4>
<p><strong>答：</strong></p>
<p>使用序列化 JSON.stringify(),判断是否强等于‘{}’:</p>
<pre><code class="language-javascript"><div><span class="hljs-keyword">var</span> obj = {};
<span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">JSON</span>.stringify(obj) === <span class="hljs-string">'{}'</span>);
</div></code></pre>
<hr>
<h4 id="%e9%97%ae%e5%a6%82%e4%bd%95%e5%88%a4%e6%96%ad%e5%af%b9%e8%b1%a1%e6%98%af%e5%90%a6%e6%9c%89%e6%9f%90%e4%b8%aa%e5%b1%9e%e6%80%a7"><strong>问：如何判断对象是否有某个属性？</strong></h4>
<p><strong>答：</strong></p>
<p>使用 ES6 中的 hasOwnProperty(),来判断是否存在某个属性。</p>
<pre><code class="language-javascript"><div><span class="hljs-keyword">var</span> obj = { <span class="hljs-attr">a</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">b</span>: <span class="hljs-number">2</span>, <span class="hljs-attr">c</span>: <span class="hljs-string">'hello'</span> };

<span class="hljs-built_in">console</span>.log(obj.hasOwnProperty(<span class="hljs-string">'c'</span>)); <span class="hljs-comment">// true</span>
<span class="hljs-built_in">console</span>.log(obj.hasOwnProperty(<span class="hljs-string">'d'</span>)); <span class="hljs-comment">// false</span>
</div></code></pre>
<hr>
<h4 id="%e9%97%ae%e6%95%b0%e7%bb%84%e9%83%bd%e6%9c%89%e5%93%aa%e4%ba%9b%e5%b8%b8%e7%94%a8%e7%9a%84%e6%96%b9%e6%b3%95"><strong>问：数组都有哪些常用的方法</strong></h4>
<p><strong>答：</strong></p>
<p>常见的有 push()、shift()、pop()、unshift()、slice()、splice()、toString()、reverse()、map()、forEach()、还有一些数组操作的告诫函数 sort()、filter()、every()、some()、reduce()等。</p>
<hr>
<p><strong>问:map()与 forEach()有什么相同处，什么不同处？</strong></p>
<p><strong>答：</strong></p>
<p>都可以对数组进行遍历，不可以使用 break、continue,跳出遍历；</p>
<p>不同点是：</p>
<p>map()遍历数组时，需要 return 每个子项，本身不改变原有数组，结果返回一个新数组；</p>
<p>forEach()遍历数组时，改变原有的数组，遍历中不需要 return。</p>
<hr>
<p><strong>问:slice()与 splice()有什么区别？</strong></p>
<p><strong>答：</strong></p>
<p>slice():从原有数组中返回选定的元素，语法为 arrayObject.slice(start[,end]),结果返回新的数组；</p>
<p>splice():删除数组指定元素，并可以添加新的元素，返回被删除的项目，改变原有数组，语法为 arrayObject(index,howmany[,item1,....,itemX])。</p>
<hr>
<h4 id="%e9%97%ae%e7%ae%80%e8%bf%b0-reduce%e7%9a%84%e4%bd%bf%e7%94%a8"><strong>问：简述 reduce()的使用</strong></h4>
<p><strong>答：</strong></p>
<p>reduce():接收一个函数作为累加器并指定初始值,然后为数组中的每一个元素依次执行回调函数，回调函数有 4 个参数：初始值（上一次回调的返回值），当前元素值，当前索引，原数组。数组元素的求和就可以使用 reduce()简单实现。</p>
<hr>
<h4 id="%e9%97%ae%e6%99%ae%e9%80%9a%e5%87%bd%e6%95%b0%e4%b8%8e%e6%9e%84%e9%80%a0%e5%87%bd%e6%95%b0%e6%9c%89%e4%bb%80%e4%b9%88%e5%8c%ba%e5%88%ab"><strong>问：普通函数与构造函数有什么区别？</strong></h4>
<p><strong>答：</strong></p>
<p>定义方式不同：普通函数通过 function fName(){ }来定义，函数名一般小写，内部一般都有返回值，使用时直接调用即可；构造函数使用 new 关键字 new Function FName()来定义,函数名一般大写，内部一般无返回值。</p>
<p>内部 this 指向不同：普通函数非严格模式指向 window,严格模式指向 undefined；构造函数内部 this 指向创建的对象实例本身。</p>
<p>返回值不同：普通函数使用 return 时， 返回具体返回值，无 return 时，返回 undefined；而构造函数一般无返回值，调用后返回实例本身，有返回值时，return 值类型时，返回忽略此值，return 引用类型时，返回该引用类型，而不是创建的实例本身。</p>
<pre><code class="language-javascript"><div><span class="hljs-comment">// 普通函数</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">foo</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-built_in">console</span>.log(<span class="hljs-keyword">this</span> === <span class="hljs-built_in">window</span>); <span class="hljs-comment">// 内部指向window</span>
  <span class="hljs-keyword">return</span> <span class="hljs-string">'foo'</span>;
}
<span class="hljs-built_in">console</span>.log(foo()); <span class="hljs-comment">// 返回返回值'foo'</span>
<span class="hljs-comment">// true</span>
<span class="hljs-comment">// 'foo'</span>

<span class="hljs-comment">// 构造函数</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Bar</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">this</span>.name = <span class="hljs-string">'bar'</span>;
  <span class="hljs-built_in">console</span>.log(<span class="hljs-keyword">this</span>); <span class="hljs-comment">//this指向实例本身：{name:'bar'}</span>
}
<span class="hljs-keyword">var</span> bar = <span class="hljs-keyword">new</span> Bar();

<span class="hljs-built_in">console</span>.log(bar); <span class="hljs-comment">// 返回实例本身</span>
<span class="hljs-built_in">console</span>.log(bar.name); <span class="hljs-comment">// 返回实例下的属性值</span>

<span class="hljs-comment">// {name:'bar'}</span>
<span class="hljs-comment">// {name:'bar'}</span>
<span class="hljs-comment">// 'bar'</span>
</div></code></pre>
<hr>
<h4 id="%e9%97%aesetmap-%e6%98%af%e4%bb%80%e4%b9%88"><strong>问：Set、Map 是什么？</strong></h4>
<p><strong>答：</strong></p>
<p>都是 ES6 中提供的新的数据结构。</p>
<p>Set 类似于数组，成员值都是唯一的，没有重复值。</p>
<p>本身是构造函数，使用 new Set()生成 Set 数据结构，</p>
<p>实例本身有 costructor、size 属性，</p>
<p>实例方法：</p>
<p>add(value):添加成员值，</p>
<p>delete(value):删除成员值，</p>
<p>has(value):判断是否为成员值，</p>
<p>clear():清除所有成员；</p>
<p>3 个遍历器生成的函数和 1 个遍历方法：</p>
<p>keys():返回一个键名遍历器，</p>
<p>values():返回一个键值遍历器，</p>
<p>entries():返回一个键值对的遍历器，</p>
<p>forEach():使用回调函数遍历每个成员。</p>
<p>Map 类似于对象，可以使用各种类型值（包括对象）作为键值。</p>
<p>键值只有严格相等才会认为是同一个键值。</p>
<p>本身具有 size 属性：返回成员总数。</p>
<p>方法有：</p>
<p>set(key,value):设置 key 对应的键值，key 已有为更新，无添加；</p>
<p>get(key):读取 key 对应的键值；</p>
<p>has(key):判断是否存在某键值；</p>
<p>delete(key):删除某个键；</p>
<p>clear():清空所有哦成员；</p>
<p>3 个遍历器生成的函数和一个遍历方法：</p>
<p>keys():返回键名的遍历器，</p>
<p>values():返回键值的遍历器，</p>
<p>entries():返回所有成员的遍历器，</p>
<p>forEach():遍历 Map 所有成员。</p>
<hr>
<h4 id="%e9%97%aesetmap-%e4%b8%8e-weaksetweakmap-%e6%9c%89%e4%bb%80%e4%b9%88%e4%b8%8d%e5%90%8c"><strong>问：Set、Map 与 WeakSet、WeakMap 有什么不同？</strong></h4>
<p><strong>答：</strong></p>
<p>WeakSet 结构与 Set 类似，也是不重复的值的集合。</p>
<p>但是它与 Set 有两个区别：</p>
<p>WeakSet 的成员只能是对象，不能是其他类型的值；</p>
<p>WeakSet 不可遍历:</p>
<p>因为，WeakSet 中的对象都是弱引用，即垃圾回收机制不考虑 WeakSet 对该对象的引用，其他对象都不在引用该对象时，垃圾回收机制会自动回收该对象所占用的内存，不考虑该对象是否还存在与 WeakSet 中。</p>
<p>WeakMap 结构与 Map 结构基本类似，只接受对象作为键名(null 除外),不接受其他类型的值作为键名，而且键名所指向的对象不计入垃圾回收机制。</p>
<p>无 size 属性，无遍历方法，无法清空，键名不计入引用，只有 4 个方法：get()、set()、has()、delete()。</p>
<hr>
<p><strong>问：类型的隐式转换有哪些?</strong><br>
<strong>答：</strong></p>
<p>常见的隐式转换：</p>
<ul>
<li>字符串连接</li>
<li>比较运算</li>
<li>算术运算</li>
<li>特殊表达式</li>
</ul>
<p>字符串连接：连接之前会将非字符串转换为字符串，再做连接运算(Symbol 值除外，会抛出异常)；</p>
<pre><code class="language-javascript"><div><span class="hljs-built_in">console</span>.log(<span class="hljs-string">'a'</span> + <span class="hljs-number">10</span>); <span class="hljs-comment">// 'a10'</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'a'</span> + <span class="hljs-number">0</span>); <span class="hljs-comment">// 'a0'</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'a'</span> + <span class="hljs-number">1</span>); <span class="hljs-comment">// 'a1'</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'a'</span> + <span class="hljs-literal">NaN</span>); <span class="hljs-comment">// 'aNaN'</span>

<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'a'</span> + <span class="hljs-literal">true</span>); <span class="hljs-comment">// 'atrue'</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'a'</span> + <span class="hljs-literal">false</span>); <span class="hljs-comment">// 'afalse'</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'a'</span> + <span class="hljs-literal">undefined</span>); <span class="hljs-comment">// 'aundefined'</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'a'</span> + <span class="hljs-literal">null</span>); <span class="hljs-comment">// 'anull'</span>

<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'a'</span> + { <span class="hljs-attr">a</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">b</span>: <span class="hljs-string">'foo'</span> }); <span class="hljs-comment">// 'a[object Object]'</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'a'</span> + <span class="hljs-built_in">Symbol</span>(<span class="hljs-string">'foo'</span>)); <span class="hljs-comment">// Uncaught TypeError: Cannot convert a Symbol value to a string</span>
</div></code></pre>
<p>比较运算:'&gt;'、'&lt;' 、'==',会调用 Number()方法，转换数值后再做比较。</p>
<p>'==='不会隐式转换类型，同时比较数值与其类型。</p>
<blockquote>
<p>特列：<br>
字符串直接的大小比较：从首位逐个对比其对应的 Unicode 编码值的大小；<br>
可以使用 charCodeAt()获取字符串中某个字符的 Unicode 值<br>
null===null 为 true，任何两个 null 都是相等的<br>
NaN===NaN 为 false，任何两个 NaN 都是不相等的</p>
<p>undefined==null 为 true</p>
</blockquote>
<pre><code class="language-javascript"><div><span class="hljs-built_in">console</span>.log(<span class="hljs-string">'a'</span> &gt; <span class="hljs-string">'b'</span>); <span class="hljs-comment">// false 比较Unicode值,97&gt;98</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'a'</span> &lt; <span class="hljs-number">10</span>); <span class="hljs-comment">// false</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'a'</span> &lt; <span class="hljs-number">10</span>); <span class="hljs-comment">// false</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'a'</span> == <span class="hljs-number">10</span>); <span class="hljs-comment">// false</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'a'</span> === <span class="hljs-number">10</span>); <span class="hljs-comment">// false</span>

<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'5'</span> &gt; <span class="hljs-string">'10'</span>); <span class="hljs-comment">// true   按照字符串比较来判断</span>

<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'10'</span> &gt; <span class="hljs-number">10</span>); <span class="hljs-comment">// fasle</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'10'</span> &lt; <span class="hljs-number">10</span>); <span class="hljs-comment">// fasle</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'10'</span> == <span class="hljs-number">10</span>); <span class="hljs-comment">// true</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'10'</span> === <span class="hljs-number">10</span>); <span class="hljs-comment">// false</span>

<span class="hljs-comment">// 特殊比较</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-literal">null</span> === <span class="hljs-literal">null</span>); <span class="hljs-comment">// true</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-literal">undefined</span> === <span class="hljs-literal">undefined</span>); <span class="hljs-comment">//true</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-literal">NaN</span> == <span class="hljs-literal">NaN</span>); <span class="hljs-comment">//false</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-literal">NaN</span> === <span class="hljs-literal">NaN</span>); <span class="hljs-comment">//false</span>

<span class="hljs-built_in">console</span>.log(<span class="hljs-literal">undefined</span> == <span class="hljs-literal">null</span>); <span class="hljs-comment">// true</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-literal">undefined</span> === <span class="hljs-literal">null</span>); <span class="hljs-comment">// false</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-literal">NaN</span> == <span class="hljs-literal">undefined</span>); <span class="hljs-comment">//false</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-literal">NaN</span> == <span class="hljs-literal">null</span>); <span class="hljs-comment">// false</span>
</div></code></pre>
<p>算术运算：会隐式的使用 Number()转换为数值型后，再做运算。</p>
<blockquote>
<p>特例：<br>
非数字的字符串与数值型数字相加，不会使用此规则，会使用字符串连接规则；<br>
Object 与数字相加，不会使用此规则，会使用字符串连接规则；<br>
数组与数字相加，不会使用此规则，会使用字符串连接规则；<br>
Symbol 值参与算术运算，会抛出异常。</p>
</blockquote>
<pre><code class="language-javascript"><div><span class="hljs-comment">// 加运算 +</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'a'</span> + <span class="hljs-number">10</span>); <span class="hljs-comment">//  'a10'   特例,直接使用字符串连接原则</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'10'</span> + <span class="hljs-number">10</span>); <span class="hljs-comment">//  20   10 + 10</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-literal">true</span> + <span class="hljs-number">10</span>); <span class="hljs-comment">// 11    1 + 10</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-literal">false</span> + <span class="hljs-number">10</span>); <span class="hljs-comment">// 10    0 + 10</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-literal">undefined</span> + <span class="hljs-number">10</span>); <span class="hljs-comment">// NaN    NaN + 10</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-literal">null</span> + <span class="hljs-number">10</span>); <span class="hljs-comment">// 10    0 + 10</span>
<span class="hljs-built_in">console</span>.log({ <span class="hljs-attr">a</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">b</span>: <span class="hljs-string">'hello'</span> } + <span class="hljs-number">10</span>); <span class="hljs-comment">// '[object Object]10'  特例：使用了字符串连接原则</span>
<span class="hljs-built_in">console</span>.log([<span class="hljs-string">'a'</span>, <span class="hljs-string">'b'</span>] + <span class="hljs-number">10</span>); <span class="hljs-comment">// 'a,b10'  特例：使用了字符串连接原则</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">Symbol</span>(<span class="hljs-string">'foo'</span>) + <span class="hljs-number">10</span>); <span class="hljs-comment">// Uncaught TypeError: Cannot convert a Symbol value to a number</span>

<span class="hljs-comment">// 减运算 -</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'a'</span> - <span class="hljs-number">10</span>); <span class="hljs-comment">//  NaN</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'10'</span> - <span class="hljs-number">10</span>); <span class="hljs-comment">//  0   10 - 10</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-literal">true</span> - <span class="hljs-number">10</span>); <span class="hljs-comment">// -9    1 - 10</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-literal">false</span> - <span class="hljs-number">10</span>); <span class="hljs-comment">// -10    0 - 10</span>
<span class="hljs-keyword">var</span> a;
<span class="hljs-built_in">console</span>.log(a - <span class="hljs-number">10</span>); <span class="hljs-comment">// NaN    NaN - 10</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-literal">null</span> - <span class="hljs-number">10</span>); <span class="hljs-comment">// -10    0 - 10</span>
<span class="hljs-built_in">console</span>.log({ <span class="hljs-attr">a</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">b</span>: <span class="hljs-string">'hello'</span> } - <span class="hljs-number">10</span>); <span class="hljs-comment">// NaN</span>
<span class="hljs-built_in">console</span>.log([<span class="hljs-string">'a'</span>, <span class="hljs-string">'b'</span>] - <span class="hljs-number">10</span>); <span class="hljs-comment">// NaN</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">Symbol</span>(<span class="hljs-string">'foo'</span>) - <span class="hljs-number">10</span>); <span class="hljs-comment">// Uncaught TypeError: Cannot convert a Symbol value to a number</span>

<span class="hljs-comment">//  /、%、+= 、 -=、  /=、  %= 与减运算-类似，也是它规则上做运算。</span>
</div></code></pre>
<p>特殊表达式: +字符串、-字符串、会把当前字符串转换为 Number，等价于 Number(字符串)，然后根据+/-对应取正负。</p>
<pre><code class="language-javascript"><div><span class="hljs-built_in">console</span>.log();

<span class="hljs-built_in">console</span>.log(+<span class="hljs-string">'a'</span>); <span class="hljs-comment">//  NaN</span>
<span class="hljs-built_in">console</span>.log(+<span class="hljs-string">'10'</span>); <span class="hljs-comment">//  10</span>
<span class="hljs-built_in">console</span>.log(+<span class="hljs-literal">true</span>); <span class="hljs-comment">// 1</span>
<span class="hljs-built_in">console</span>.log(+<span class="hljs-literal">false</span>); <span class="hljs-comment">// 0</span>
<span class="hljs-built_in">console</span>.log(+<span class="hljs-literal">undefined</span>); <span class="hljs-comment">// NaN</span>
<span class="hljs-built_in">console</span>.log(+<span class="hljs-literal">null</span>); <span class="hljs-comment">// 0</span>
<span class="hljs-built_in">console</span>.log(+{ <span class="hljs-attr">a</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">b</span>: <span class="hljs-string">'hello'</span> }); <span class="hljs-comment">// NaN</span>
<span class="hljs-built_in">console</span>.log(+[<span class="hljs-string">'a'</span>, <span class="hljs-string">'b'</span>]); <span class="hljs-comment">// NaN</span>
<span class="hljs-built_in">console</span>.log(+<span class="hljs-built_in">Symbol</span>(<span class="hljs-string">'foo'</span>)); <span class="hljs-comment">// Uncaught TypeError: Cannot convert a Symbol value to a number</span>

<span class="hljs-built_in">console</span>.log(-<span class="hljs-string">'a'</span>); <span class="hljs-comment">//  NaN</span>
<span class="hljs-built_in">console</span>.log(-<span class="hljs-string">'10'</span>); <span class="hljs-comment">//  -10</span>
<span class="hljs-built_in">console</span>.log(-<span class="hljs-literal">true</span>); <span class="hljs-comment">// -1</span>
<span class="hljs-built_in">console</span>.log(-<span class="hljs-literal">false</span>); <span class="hljs-comment">// -0    与0等价：-false===0 为true</span>
<span class="hljs-built_in">console</span>.log(-<span class="hljs-literal">undefined</span>); <span class="hljs-comment">// NaN</span>
<span class="hljs-built_in">console</span>.log(-<span class="hljs-literal">null</span>); <span class="hljs-comment">// -0     与0等价: -null===0 为true</span>
<span class="hljs-built_in">console</span>.log(-{ <span class="hljs-attr">a</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">b</span>: <span class="hljs-string">'hello'</span> }); <span class="hljs-comment">// NaN</span>
<span class="hljs-built_in">console</span>.log(-[<span class="hljs-string">'a'</span>, <span class="hljs-string">'b'</span>]); <span class="hljs-comment">// NaN</span>
<span class="hljs-built_in">console</span>.log(-<span class="hljs-built_in">Symbol</span>(<span class="hljs-string">'foo'</span>)); <span class="hljs-comment">// Uncaught TypeError: Cannot convert a Symbol value to a number</span>
</div></code></pre>
<p>以上是围绕 JS 数据类型常问到的面试题。</p>
<p><img src="https://s1.ax1x.com/2020/03/30/GnwTeI.gif" alt="GnwTeI.gif"></p>

    </body>
    </html>